﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;

namespace DocumentAnalyzer
{
	public partial class AnalyzerGUI : Form
	{
		private static string OriginName = "Document Analyzer";
		private static string NamePlusFilename = OriginName + " - {0}";
		private Bitmap _bmp, _unMarkedBMP;
		private Histogram[] _histData;
		private bool[][] _pixelMatrix;
		private string _filename;
		private int _divisions;
		private TextLine[] _textLines;
		private bool _dirtyDivs, _dirtyLineMargine, _dirtyTextLineMargine, _dirtyFile;

		public AnalyzerGUI()
		{
			Analyzer.PossibleLineMargine = 5;
			Analyzer.MinimumTextLineLength = 150;
			InitializeComponent();
			Divs();
		}

		private void loadImageButton_Click(object sender, EventArgs e)
		{
			try
			{
				if (imageLoadFileDialog.ShowDialog() != DialogResult.OK) return;
				_filename = imageLoadFileDialog.FileName;
				var fi = new FileInfo(_filename);
				Report(string.Format("Using file: {0}", _filename));
				Text = string.Format(NamePlusFilename, fi.Name);
				textLineMarkGroupBox.Enabled = false;
				_dirtyFile = true;
				_dirtyDivs = true;
				_dirtyLineMargine = true;
				_dirtyTextLineMargine = true;
				analyzeFileButton.Enabled = true;
				_unMarkedBMP = Analyzer.ProcessFile(_filename);
				//ProcessFile();
				if (_unMarkedBMP == null) throw new Exception("No file opened");
				pictureBox.Image = _unMarkedBMP;
				divisionsNumericUpDown.Value = _unMarkedBMP.Width / histogramLengthNumericUpDown.Value;
			}
			catch (Exception ex)
			{
				ReportError(ex.Message);
			}
		}

		private void ReportError(string error)
		{
			Report(string.Format("Error: {0}", error));
		}

		private void Report(string report)
		{
			Invoke(new Action<string>(_Report), report);
		}

		private void _Report(string report)
		{
			loggingTextBox.AppendText(string.Format("{0} {1}\r\n", DateTime.Now.ToString("HH:mm:ss.fff"), report));
		}

		private void DrawHistogram(Histogram hist, int maxX)
		{
			if (hist == null) return;
			
			var g = histPictureBox.CreateGraphics();
			g.FillRectangle(Brushes.White, histPictureBox.ClientRectangle);
			for (int h = 0; h < hist.Length; h++)
			{
				if (hist[h] == 0) continue;
				int x = (int)(((double)h * (histPictureBox.Width) / (hist.Length)));
				int y = (int)((hist[h] * (histPictureBox.Height) / (double)maxX));
				g.DrawLine(Pens.Black, x, histPictureBox.Height, x, histPictureBox.Height-y);
			}
			g.Flush();
			g.Dispose();
		}

		private void analyzeFileButton_Click(object sender, EventArgs e)
		{
			try
			{
				Line[][] lines=null;
				if (_dirtyFile)
				{
					Report("Analyzing file:");					
					Report("Filling pixel matrix");
					_pixelMatrix = Analyzer.FillPixelMatrix(_unMarkedBMP);
				}
				if (_dirtyDivs || _dirtyFile)
				{
					Report("Creating histograms");
					_histData = Analyzer.CreateHistograms(_pixelMatrix, _divisions);
				}
				if (_dirtyTextLineMargine || _dirtyLineMargine || _dirtyDivs || _dirtyFile)
				{
					Report("Finding lines for each histogram");

					lines = Analyzer.FindPossibleLines(_histData);
				
					Report(string.Format("Analyzing lines (margines: {0} {1})", Line.MargineX, Line.MargineY));

					_textLines = Analyzer.AnalyzeLines(lines);
					Analyzer.SortTextLines(ref _textLines);

					lineNumericUpDown.Value = 1;
					lineNumericUpDown.Maximum = _textLines.Length;
					textLineMarkGroupBox.Enabled = true;

					Report(string.Format("Found {0} text lines", _textLines.Length));

					pictureBox.Image = _unMarkedBMP;
				}
				_dirtyFile = false;
				_dirtyDivs = false;
				_dirtyLineMargine = false;
				_dirtyTextLineMargine = false;
				Report("All done");
				analyzeFileButton.Enabled = false;
			}
			catch (Exception ex)
			{
				ReportError(ex.Message);
			}
		}

		private void MarkTextLine(Bitmap bmp, TextLine textLine, Color color)
		{
			for (int i = 0; i < textLine.NumberOfLines; i++)
			{
				MarkLinePart(bmp, textLine[i], color);
			}
		}

		private void MarkLinePart(Bitmap bmp, Line line, Color color)
		{
			if (line == null || bmp == null) return;

			int h = bmp.Height, w = bmp.Width;

			for (int x = line.X_Start; x < line.X_End; x++)
			{
				bmp.SetPixel(x, line.Y_Start, color);
				bmp.SetPixel(x, line.Y_End, color);
			}
		}

		private void divisionsNumericUpDown_ValueChanged(object sender, EventArgs e)
		{
			Divs();
		}
		
		private void Divs()
		{
			_divisions = decimal.ToInt32(divisionsNumericUpDown.Value);
			_dirtyDivs = true;
			_dirtyLineMargine = true;
			_dirtyTextLineMargine = true;
			if (_filename != string.Empty) analyzeFileButton.Enabled = true;
		}

		private void pictureBox_MouseClick(object sender, MouseEventArgs e)
		{
			int div = (int)(((double)e.X / pictureBox.Width) * _divisions);
			Report(string.Format("Div #{0}", div));
			DrawHistogram(_histData[div], (int)(_pixelMatrix.Length/_divisions));
		}

		private void markLineButton_Click(object sender, EventArgs e)
		{
			_bmp = new Bitmap(_unMarkedBMP);
			MarkTextLine(_bmp, _textLines[decimal.ToInt32(lineNumericUpDown.Value) - 1], Color.Red);
			pictureBox.Image = _bmp;
		}

		private void margineNumericUpDown_ValueChanged(object sender, EventArgs e)
		{
			_dirtyLineMargine = true;
			//_possibleLineMargine = decimal.ToInt32(margineNumericUpDown.Value);
			Analyzer.PossibleLineMargine = decimal.ToInt32(margineNumericUpDown.Value);
			analyzeFileButton.Enabled = true;
		}

		private void xyMarginesNumericUpDown_ValueChanged(object sender, EventArgs e)
		{
			_dirtyTextLineMargine = true;
			Line.MargineX = decimal.ToInt32(xMargineNumericUpDown.Value);
			Line.MargineY = decimal.ToInt32(yMargineNumericUpDown.Value);
			analyzeFileButton.Enabled = true;
		}

		private void lineNumericUpDown_ValueChanged(object sender, EventArgs e)
		{
			markLineButton_Click(sender, e);
		}

		private void saveLineButton_Click(object sender, EventArgs e)
		{
			
			int lineNumber=decimal.ToInt32(lineNumericUpDown.Value);
			var fi = new FileInfo(_filename);
			string originalFilename = fi.Name;
			originalFilename = originalFilename.Remove(originalFilename.IndexOf(fi.Extension));
			string outputFilename = string.Format("{0} - Line {1}{2}", originalFilename, lineNumber, fi.Extension);
			var tl = _textLines[lineNumber - 1];
			Report(string.Format("Saving line #{0} to file {1}", lineNumber, outputFilename));
			var success = tl.SaveToFile(outputFilename, _unMarkedBMP);
			if (success==string.Empty)
				Report("File saved");
			else ReportError(success);
		}

		private void histogramLengthNumericUpDown_ValueChanged(object sender, EventArgs e)
		{
			if (_unMarkedBMP == null) return;
			int w = _unMarkedBMP.Width;
			divisionsNumericUpDown.Value = w / histogramLengthNumericUpDown.Value;
		}
	}
	
}
